package com.zhuhjay.common.redis.util;

import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.RandomUtil;
import com.zhuhjay.common.base.util.JacksonUtils;
import com.zhuhjay.common.base.util.SpringContextHolder;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.RedisScript;

import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import static com.zhuhjay.common.base.constant.TimeConstant.*;

/**
 * @author ZhuHJay
 * @date 2023/2/25 11:08
 */
public class RedisUtils {

    private static final StringRedisTemplate TEMPLATE;
    static {
        TEMPLATE = SpringContextHolder.getBean(StringRedisTemplate.class);
    }

    // ==============================操作key============================

    /** 修改缓存，并不改变其过期时间 */
    public static void setCache(String key, Object value) {
        if (value instanceof String) {
            // BUG: set(key, value, offset) 方法的 offset 是从指定位置覆盖内容, 非过期时间
            TEMPLATE.opsForValue().set(key, (String) value);
        } else {
            TEMPLATE.opsForValue().set(key, JacksonUtils.writeValueAsString(value));
        }
    }

    public static void setCacheAndExpire(String key, Object value, long millis) {
        setCacheAndExpire(key, value, millis, TimeUnit.MILLISECONDS);
    }

    /** 修改缓存，并改变其过期时间(过期时间不加随机过期时间) */
    public static void setCacheAndExpire(String key, Object value, long timeout, TimeUnit timeUnit) {
        if (value instanceof String) {
            TEMPLATE.opsForValue().set(key, (String) value, timeout ,timeUnit);
        } else {
            TEMPLATE.opsForValue().set(key, JacksonUtils.writeValueAsString(value), timeout, timeUnit);
        }
    }

    /** 修改缓存，并改变其过期时间(过期时间加随机过期时间(0, 5]分钟) */
    public static void setCacheAndExpireRan(String key, Object value, long timeout, TimeUnit timeUnit) {
        long millis = timeUnit.toMillis(timeout) + RandomUtil.randomInt(5 * MINUTE);
        setCacheAndExpire(key, value, millis);
    }

    /** 获取缓存 */
    public static String getCache(String key) {
        return TEMPLATE.opsForValue().get(key);
    }

    /** 将key对应的值自增 **/
    public static Long increment(String key) {
        return TEMPLATE.opsForValue().increment(key);
    }

    // ==============================操作list============================

    /** 获取list缓存的数据 **/
    public static List<String> getMembers4List(String key) {
        return TEMPLATE.opsForList().range(key, 0, -1);
    }

    /** 将values放入list缓存 **/
    public static void addValues2List(String key, Object... values) {
        if (values == null || values.length == 0) {
            return;
        }
        String[] strings = Arrays.stream(values).map(JacksonUtils::writeValueAsString).toArray(String[]::new);
        TEMPLATE.opsForList().rightPushAll(key, strings);
    }

    // ==============================操作set============================

    /** 获取set缓存的数据 **/
    public static Set<String> getMembers4Set(String key) {
        return TEMPLATE.opsForSet().members(key);
    }

    /** 是否存在value在set缓存中 **/
    public static boolean hasValueInSet(String key, Object value) {
        return BooleanUtil.isTrue(TEMPLATE.opsForSet().isMember(key, value));
    }

    /** 添加value到set缓存中 **/
    public static void addValue2Set(String key, String... value) {
        TEMPLATE.opsForSet().add(key, value);
    }

    /** 将value从set缓存中删除 **/
    public static void removeValue4Set(String key, String value) {
        TEMPLATE.opsForSet().remove(key, value);
    }

    /** 获取set缓存的长度 **/
    public static Long getSize4Set(String key) {
        return TEMPLATE.opsForSet().size(key);
    }

    // ==============================公共操作============================

    /** 修改key过期时间 */
    public static void setKeyExpire(String key, long timeout, TimeUnit timeUnit) {
        TEMPLATE.expire(key, timeout, timeUnit);
    }

    /** 修改key过期时间, 短期保存 1天 + [0, 5)分钟 */
    public static void setKeyExpireShort(String key) {
        TEMPLATE.expire(key,
                DAY + RandomUtil.randomInt(5 * MINUTE),
                TimeUnit.MILLISECONDS);
    }

    /** 修改key过期时间, 中期保存 7天 + [0, 25)分钟 */
    public static void setKeyExpireMiddle(String key) {
        TEMPLATE.expire(key,
                WEEK + RandomUtil.randomInt(25 * MINUTE),
                TimeUnit.MILLISECONDS);
    }

    /** 修改key过期时间, 长期保存 30天 + [0, 45)分钟 */
    public static void setKeyExpireLong(String key) {
        TEMPLATE.expire(key,
                MONTH + RandomUtil.randomInt(45 * MINUTE),
                TimeUnit.MILLISECONDS);
    }

    /** 删除缓存 */
    public static void deleteCache(String key) {
        TEMPLATE.delete(key);
    }

    /** 获取keys */
    public static Set<String> getKeys(String prefix) {
        return TEMPLATE.keys(prefix);
    }

    /** 执行 Lua 脚本 */
    public static <T> T execute(RedisScript<T> script, List<String> keys, Object... args) {
        return TEMPLATE.execute(script, keys, args);
    }

    /** 判断是否存在key */
    public static boolean hasKey(String key) {
        return getCache(key) != null;
    }
}
